package core

import (
	"errors"
	"github.com/jsen-joker/gend/core/config"
	"github.com/jsen-joker/gend/core/entity"
	"github.com/jsen-joker/gend/core/populate"
	"github.com/jsen-joker/gend/core/provider"
	"github.com/jsen-joker/gend/core/utils"
	"strconv"
)

type DefaultGendService struct {
	populate.IdPopulate
	provider.MachineIdProvider
	//populate populate.IdPopulate

	config *config.GendConfig
	timer *utils.Timer
}

func (gs *DefaultGendService) Init() error {
	defaultConfig := config.GetDefaultConfigInstance()
	gs.initPopulate(*defaultConfig)
	gs.initProvider(*defaultConfig)
	gs.config = config.NewGendConfig()
	gs.config.Machine = gs.MachineIdProvider.GenMachineId()
	gs.config.Init()
	err := gs.validateMachineId(*gs.config); if err != nil {
		println(err.Error())
		gs.config.Machine = 0
	}
	gs.timer = utils.NewTimer(gs.config)
	return gs.timer.Init()
}
// 获取id
func (gs DefaultGendService) GenId() int64 {
	id := &entity.ID {
		Version: gs.config.Version,
		Type: gs.config.IdType,
		Gen: gs.config.Gen,
		Machine: gs.config.Machine,
	}
	// lock 计算 serial和 Time
	gs.populateId(id)
	return utils.Encode(*id, gs.config)
}
// 解码 id
func (gs DefaultGendService) ExpId(id int64) entity.ID {
	return *utils.Decode(id, gs.config)
}

func (gs DefaultGendService) populateId(id *entity.ID) {
	err := gs.Populate(gs.timer, gs.config, id)
	if err != nil {
		print("error")
	}
}
func (gs *DefaultGendService)initPopulate(config config.DefaultConfig)  {
	p := config.Populate
	if p == "lock" {
		gs.IdPopulate = populate.NewLockPopulate()
	} else {
		gs.IdPopulate = populate.NewLockPopulate()
	}
}
func (gs *DefaultGendService)initProvider(config config.DefaultConfig)  {
	p := config.Provider
	if p == "default" {
		gs.MachineIdProvider = provider.NewDefaultMachineIdProvider(config.Machine)
	} else {
		gs.MachineIdProvider = provider.NewDefaultMachineIdProvider(config.Machine)
	}
}
func (gs *DefaultGendService) validateMachineId(config config.GendConfig) error {
	machineId := config.Machine
	if machineId < 0 || machineId >= 1<<config.MachineBits  {
		return errors.New("machine id is invalidate : " + strconv.FormatInt(machineId, 10))
	}
	return nil
}

func NewDefaultGendService() GendService  {
	gs := &DefaultGendService{}
	err := gs.Init()
	if err != nil {
		println(err)
	}
	return gs
}